package com.dragon.app.concurrent;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 
 * <p>class: ProductorConsumer</p>  
 * <p>Description: 生产者消费者Lock版</p>  
 * @author SmallDragon
 * @date 2019年5月6日
 *
 */
public class ProductorConsumer {

	public static void main(String[] args) {
		Clerk clerk = new Clerk();

		new Thread(new Productor(clerk)).start();
		new Thread(new Consumer(clerk)).start();
		new Thread(new Consumer(clerk)).start();

	}

	static class Clerk {
		int product = 5;
		private Lock lock = new ReentrantLock();
		private Condition condition;

		{
			condition = lock.newCondition();
		}

		// 记住，wait()外面一定要有synchronized，获得监视器；
		// 还要有while来做条件判断，因为线程醒了之后不一定满足条件。防止虚假唤醒
		public void recieve() {
			lock.lock();
			try {
				while (product >= 20) {
					condition.await();
				}
				product++;
				System.out.println(Thread.currentThread().getName() + ":生产了第" + product + "个商品。。");
				condition.signalAll();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}

		public void sale() {
			lock.lock();
			try {
				while (product <= 0) {
					condition.await();
				}
				System.out.println(Thread.currentThread().getName() + "：消费了第" + product + "个商品。。");
				product--;
				condition.signalAll();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}
	}

	static class Productor implements Runnable {
		Clerk clerk;

		public Productor() {
			super();
		}

		public Productor(Clerk clerk) {
			super();
			this.clerk = clerk;
		}

		@Override
		public void run() {
			while (true) {
				clerk.recieve();
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

	}

	static class Consumer implements Runnable {
		Clerk clerk;

		public Consumer() {
			super();
		}

		public Consumer(Clerk clerk) {
			super();
			this.clerk = clerk;
		}

		@Override
		public void run() {
			while (true) {
				clerk.sale();
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

	}

}
